# ~*~ coding: utf-8 ~*~
from flask import request, views, render_template, jsonify
from flask_login import current_user

from apps.common.utils import fill_date_to_timestamp, timestamp_obj_to_str, list2dict
from apps.common.mixin import CompatibleWithSelect2Mixin
from apps.extensions import db
from apps.common import response
from apps.common.utils import generate_uuid
from apps.perms.mixin import LoginRequiredMixin
from ..models import Project, Task, Environment, Label
from ..forms import TaskForm
from ..mixin import TaskPermissionMixin


__all__ = [
    'TaskListAPI', 'TaskListView', 'TaskDeleteView', 'TaskCreateView',
    'TaskDeployView', 'TaskRollbackView', 'TaskAuditAPI', 'TaskAuditView',
    'TaskAuditApprovalAPI', 'TaskAuditRefuseAPI'
]


class TaskListAPI(CompatibleWithSelect2Mixin, TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-list'

    def get_queryset(self):
        project_ids = self.get_filter()
        if request.args.get('project'):
            project_id = request.args.get('project')
            if project_id in project_ids:
                # 用户筛选的过滤条件
                return db.session.query(Task).filter(Task.project_id == project_id)

        # 默认权限的过滤条件
        return db.session.query(Task).filter(Task.project_id.in_(project_ids))

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                ('title', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions = []
            order_by_list = None
            search = request.values.get('search')
            filter = request.values.get('filter')
            page = request.values.get('page')
            if search:
                filter_conditions.append(('name', 'like', search))
            if filter:
                filter_conditions.append(('id', 'in', filter.split(',')))
            if page:
                limit = 12
                offset = (int(page) - 1) * limit
            else:
                limit = None
                offset = 0

        tasks, count = Task.get_queryset(queryset=self.get_queryset(),
                                         filter_conditions=filter_conditions,
                                         order_by_list=order_by_list,
                                         offset=offset, limit=limit)

        # 关联查询所属项目信息
        task_ids = [task.id for task in tasks]
        projects_dict = db.session.query(Task.id, Project.name).\
            join(Project, Task.project_id == Project.id).\
            filter(Task.id.in_(task_ids)).\
            all()
        projects_dict = list2dict(projects_dict)

        results = list()
        for task in tasks:
            if task.action == Task.ACTION_DEPLOY:
                revision = task.tag if task.tag else '{}({})'.format(task.branch, task.commit),
            elif task.action == Task.ACTION_ROLLBACK:
                revision = '-'

            results.append({
                'id': task.id,
                'project': projects_dict.get(task.id),
                'title': task.title,
                'revision': revision,
                'action': task.action,
                'status': task.status,
                'create_by': task.create_by,
                'approval_user': task.approval_user if task.approval_user else '-',
                'create_time': timestamp_obj_to_str(task.create_time)
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class TaskListView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-list'

    def get(self):
        return render_template('codes/task_list.html')


class TaskCreateView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-create'

    def get(self):
        project_ids = self.get_filter()
        project_infos = db.session.query(
            Project.id.label('pid'), Project.name.label('pname'), Environment.id.label('eid'),
            Environment.name.label('ename'), Label.id.label('gid'), Label.name.label('gname')
        ). \
            outerjoin(Environment, Project.environment_id == Environment.id). \
            outerjoin(Label, Project.label_id == Label.id).\
            filter(Project.id.in_(project_ids)).\
            all()

        """ 构建以下数据结果
        data = {
            'eid': {
                'ename': '',
                'child': {
                    'gid': {
                        'gname': '',
                        'child': [
                            {'pid': '', 'pname': ''},
                            {'pid': '', 'pname': ''}
                        ]
                    },

                    'gid2': {
                        'gname': '',
                        'child': [
                            {'pid': '', 'pname': ''},
                            {'pid': '', 'pname': ''}
                        ]
                    }
                }
            },
            'eid2': {}
        }
        """
        data = {}
        for info in project_infos:
            environment_id = info.eid
            environment_name = info.ename
            group_name = info.gname
            group_id = info.gid
            project_id = info.pid
            project_name = info.pname

            if not group_id:
                group_id = generate_uuid()
                group_name = '暂无项目组'

            if environment_id not in data.keys():
                data[environment_id] = {
                    'ename': environment_name,
                    'child': {
                        group_id: {
                            'gname': group_name,
                            'child': [
                                {'pid': project_id, 'pname': project_name}
                            ]
                        }
                    }
                }
            else:
                if group_id not in data[environment_id]['child'].keys():
                    data[environment_id]['child'][group_id] = {
                        'gname': group_name,
                        'child': [
                            {'pid': project_id, 'pname': project_name}
                        ]
                    }
                else:
                    data[environment_id]['child'][group_id]['child'].append(
                        {'pid': project_id, 'pname': project_name}
                    )
        content = {
            'data': data
        }
        return render_template('codes/task_create.html', **content)

    def post(self):
        form = TaskForm(request.values)
        if form.validate():
            _clean_data = form.data
            task = Task()

            # 项目不需要进行审核，新工单直接为APPROVA状态
            project_id = _clean_data.pop('project_id')
            project = db.session.query(Project).get(project_id)
            if project.task_audit == Project.TASK_AUDIT_DISABLE:
                task.status = Task.STATUS_APPROVAL

            task.project_id = project_id
            task.title = _clean_data['title']
            task.content = _clean_data['content']
            task.tag = _clean_data['tag']
            task.branch = _clean_data['branch']
            task.commit = _clean_data['commit']
            task.create_by = current_user.name
            task.user_id = current_user.id
            db.session.add(task)
            db.session.commit()
            return response.success()
        else:
            return response.params_error(form.get_error())


class TaskDeleteView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-delete'

    def post(self, pk):
        instance = db.session.query(Task).get(pk)
        instance.delete()
        return response.success()


class TaskDeployView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-deploy'

    def get(self, pk):
        instance = db.session.query(Task).get(pk)
        content = {
            'task_id': instance.id
        }
        if not instance.is_deploy:
            return render_template('codes/task_deploy_error.html', **content)
        return render_template('codes/task_deploy.html', **content)


class TaskRollbackView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-task-rollback'

    def get(self, pk):
        instance = db.session.query(Task).get(pk)
        content = {
            'task_id': instance.id
        }
        if not instance.is_rollback:
            return render_template('codes/task_rollback_error.html', **content)
        return render_template('codes/task_rollback.html', **content)


# ---------- Audit ----------


class TaskAuditAPI(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-audit-list'

    def get_queryset(self):
        project_ids = self.get_filter()
        if request.args.get('project'):
            project_id = request.args.get('project')
            if project_id in project_ids:
                # 用户筛选的过滤条件
                return db.session.query(Task).filter(Task.project_id == project_id)

        # 默认权限的过滤条件
        return db.session.query(Task).filter(Task.project_id.in_(project_ids))

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                ('title', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        type = request.values.get('type')
        if type == 'select2':
            page = request.values.get('page')
            name = request.values.get('name')
            filter_conditions = [('name', 'like', name), ]
            order_by_list = None
            default_limit = 12
            offset = (int(page) - 1) * default_limit

        queryset = self.get_queryset().filter(Task.action == Task.ACTION_DEPLOY, Task.status == Task.STATUS_NEW)
        tasks, count = Task.get_queryset(
            queryset=queryset,
            filter_conditions=filter_conditions,
            order_by_list=order_by_list,
            offset=offset, limit=limit
        )

        # 关联查询所属项目信息
        task_ids = [task.id for task in tasks]
        projects_dict = db.session.query(Task.id, Project.name).\
            join(Project, Task.project_id == Project.id).\
            filter(Task.id.in_(task_ids)).\
            all()
        projects_dict = list2dict(projects_dict)

        results = list()
        for task in tasks:
            if task.action == Task.ACTION_DEPLOY:
                revision = task.tag if task.tag else '{}({})'.format(task.branch, task.commit),
            elif task.action == Task.ACTION_ROLLBACK:
                revision = '-'

            results.append({
                'id': task.id,
                'project': projects_dict.get(task.id),
                'title': task.title,
                'revision': revision,
                'action': task.action,
                'status': task.status,
                'create_by': task.create_by,
                'create_time': timestamp_obj_to_str(task.create_time)
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class TaskAuditView(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-audit-list'

    def get(self):
        return render_template('codes/task_audit.html')


class TaskAuditApprovalAPI(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-audit-approval'

    def post(self, pk):
        instance = db.session.query(Task).get(pk)
        instance.update(status=Task.STATUS_APPROVAL, approval_user=current_user.name)
        return response.success()


class TaskAuditRefuseAPI(TaskPermissionMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'codes-audit-refuse'

    def post(self, pk):
        instance = db.session.query(Task).get(pk)
        instance.update(status=Task.STATUS_REJECT, approval_user=current_user.name)
        return response.success()
